﻿using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Architecture;
using YJKGeometryFuncs;

namespace YJKPatternSign.StairsRoomPlanSign.ModelLayer
{
	public class StairsWellUnitPacker : BaseShapePacker
	{
		public List<StairsRunPacker> LstStairsRunPacker
		{
			get
			{
				return this.m_lstStairsRunPacker;
			}
			private set
			{
				this.m_lstStairsRunPacker = value;
			}
		}

		public StairsWellUnitPacker(Stairs inputStairs, StairsRunPacker inputPackerOne, StairsRunPacker inputPackerTwo) : base(inputStairs, StairsWellUnitPacker.GetShapeCurvesByStairsRun(inputPackerOne, inputPackerTwo))
		{
			this.LstStairsRunPacker.Add(inputPackerOne);
			this.LstStairsRunPacker.Add(inputPackerTwo);
		}

		public bool TryGetEvacuationRadiusInformation(out List<EvacuationRadiusInformationBean> lstevacuationRadius)
		{
			lstevacuationRadius = new List<EvacuationRadiusInformationBean>();
			XYZ xyz = null;
			XYZ xyz2 = null;
			for (int i = 0; i < 2; i++)
			{
				List<XYZ> lstPoints;
				Line projectLine;
				this.CalculateRunValue(out xyz, out xyz2, i, out lstPoints, out projectLine);
				XYZ xyz3;
				if (!this.TryFindCenterPoint(lstPoints, projectLine, out xyz3))
				{
					return false;
				}
				if (xyz.IsAlmostEqualTo(xyz3) || xyz2.IsAlmostEqualTo(xyz3))
				{
					return false;
				}
				XYZ xyz4 = xyz;
				if (Geometry.LessThan(xyz2.DistanceTo(xyz3), xyz.DistanceTo(xyz3)))
				{
					xyz4 = xyz2;
				}
				double num = xyz3.DistanceTo(xyz4);
				XYZ xyz5 = xyz3 + (xyz3 - xyz4).Normalize() * num;
				XYZ xyz6 = xyz3.Add(this.LstStairsRunPacker[1 - i].LstDriection[0] * num);
				Arc item = Arc.Create(xyz4, xyz5, xyz6);
				lstevacuationRadius.Add(new EvacuationRadiusInformationBean(new List<Curve>
				{
					item
				}));
			}
			return true;
		}

		private void CalculateRunValue(out XYZ usePointStart, out XYZ usePointEnd, int useIndex, out List<XYZ> lstPoints, out Line projectLine)
		{
			XYZ maxPoint = null;
			XYZ minPoint = null;
			StairsRunPacker stairsRunPacker = this.LstStairsRunPacker[0];
			StairsRunPacker stairsRunPacker2 = this.LstStairsRunPacker[1];
			lstPoints = new List<XYZ>();
			List<Line> list = new List<Line>();
			int inputIndex;
			if (useIndex == 0)
			{
				inputIndex = 1;
			}
			else
			{
				inputIndex = 0;
			}
			list.Add(stairsRunPacker.GetStairRunEndCurve(useIndex, false) as Line);
			list.Add(stairsRunPacker2.GetStairRunEndCurve(inputIndex, false) as Line);
			XYZ averticalVector = Utility.GetAVerticalVector(this.LstStairsRunPacker[useIndex].LstDriection[0], false);
			foreach (Line line in list)
			{
				lstPoints.Add(line.GetEndPoint(0));
				lstPoints.Add(line.GetEndPoint(1));
			}
			projectLine = Line.CreateUnbound(lstPoints[0], averticalVector);
			this.FindWidthPoint(lstPoints, projectLine, ref maxPoint, ref minPoint);
			this.CalculateLengthPoint(this.LstStairsRunPacker[1 - useIndex], maxPoint, minPoint, out usePointStart, out usePointEnd);
		}

		private void CalculateLengthPoint(StairsRunPacker inputRun, XYZ maxPoint, XYZ minPoint, out XYZ usePointStart, out XYZ usePointEnd)
		{
			Line line = Line.CreateUnbound(inputRun.LstUsePath[0].GetEndPoint(1), inputRun.LstDriection[0]);
			if (line.Project(maxPoint).Parameter > line.Project(minPoint).Parameter)
			{
				usePointStart = maxPoint;
				usePointEnd = minPoint.Add(inputRun.LstDriection[0] * (line.Project(maxPoint).Parameter - line.Project(minPoint).Parameter));
				return;
			}
			usePointStart = minPoint;
			usePointEnd = maxPoint.Add(inputRun.LstDriection[0] * (line.Project(minPoint).Parameter - line.Project(maxPoint).Parameter));
		}

		private void FindWidthPoint(List<XYZ> lstPoints, Line projectLine, ref XYZ maxPoint, ref XYZ minPoint)
		{
			double num = double.MinValue;
			double num2 = double.MaxValue;
			foreach (XYZ xyz in lstPoints)
			{
				if (projectLine.Project(xyz).Parameter > num)
				{
					num = projectLine.Project(xyz).Parameter;
					maxPoint = xyz;
				}
				else if (projectLine.Project(xyz).Parameter < num2)
				{
					num2 = projectLine.Project(xyz).Parameter;
					minPoint = xyz;
				}
			}
		}

		private bool TryFindCenterPoint(List<XYZ> lstPoints, Line projectLine, out XYZ findCenterPoint)
		{
			List<XYZ> list = new List<XYZ>();
			Line useLine = projectLine;
			findCenterPoint = null;
			if (projectLine.IsBound)
			{
				useLine = (projectLine.Clone() as Line);
				useLine.MakeUnbound();
			}
			foreach (XYZ xyz in lstPoints)
			{
				list.Add(useLine.Project(xyz).XYZPoint);
			}
			list = (from k in list
			orderby useLine.Project(k).Parameter
			select k).ToList<XYZ>();
			if (list.Count == 0)
			{
				return false;
			}
			if (list.Count % 2 == 0)
			{
				findCenterPoint = (list[(list.Count - 1) / 2] + list[1 + (list.Count - 1) / 2]) / 2.0;
			}
			else
			{
				findCenterPoint = list[(list.Count - 1) / 2];
			}
			return true;
		}

		private static List<Curve> GetShapeCurvesByStairsRun(StairsRunPacker inputPackerOne, StairsRunPacker inputPackerTwo)
		{
			List<Curve> list = new List<Curve>();
			list.AddRange(inputPackerOne.LstAllShapeCurve);
			list.AddRange(inputPackerTwo.LstAllShapeCurve);
			return list;
		}

		public override void AddAppendCurves(ref List<Curve> useCurve)
		{
			foreach (StairsRunPacker stairsRunPacker in this.LstStairsRunPacker)
			{
				useCurve.AddRange(stairsRunPacker.LstAddedCurves);
			}
		}

		private List<StairsRunPacker> m_lstStairsRunPacker = new List<StairsRunPacker>();
	}
}
